package com.mdb.open.trade.resource.trade;

import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mdb.bc.api.data.ListResultEx;
import com.mdb.bc.api.data.ResultEx;
import com.mdb.bc.api.enums.OrderByEnum;
import com.mdb.bc.cache.sequence.util.SequenceGenerator;
import com.mdb.bc.logger.LogAnnotation;
import com.mdb.bc.utils.ObjectUtil;
import com.mdb.bc.web.RepeatSubmitTypeEnum;
import com.mdb.bc.web.annotation.DenyRepeatSubmit;
import com.mdb.bc.web.support.SuperResources;
import com.mdb.common.work.order.dto.FinancialServiceApply;
import com.mdb.common.work.order.dto.WorkOrderCreateDto;
import com.mdb.common.work.order.producer.WorkOrderProducer;
import com.mdb.enums.PlatformRetCodeEnum;
import com.mdb.enums.product.ProductCodeEnum;
import com.mdb.enums.workOrder.OrderTypeEnum;
import com.mdb.open.common.enums.DataChannelEnum;
import com.mdb.open.common.enums.TfSequenceEnum;
import com.mdb.open.common.enums.TradeWebErrorCodeEnum;
import com.mdb.open.common.enums.trade.status.*;
import com.mdb.open.common.enums.trade.type.*;
import com.mdb.open.trade.config.TradeOpenProperties;
import com.mdb.open.trade.constant.trade.Fields;
import com.mdb.open.trade.domain.bo.trade.*;
import com.mdb.open.trade.domain.dto.trade.*;
import com.mdb.open.trade.domain.po.trade.*;
import com.mdb.open.trade.domain.vo.trade.*;
import com.mdb.open.trade.facade.trade.LoanApplyFlowFacade;
import com.mdb.open.trade.facade.trade.TradeFileFacade;
import com.mdb.open.trade.feign.CustomerClient;
import com.mdb.open.trade.feign.dto.StartRiskModelDto;
import com.mdb.open.trade.feign.vo.cus.CustBaseInfoVo;
import com.mdb.open.trade.rabbit.model.RiskProviderMo;
import com.mdb.open.trade.rabbit.provider.RiskTradeApplyProvider;
import com.mdb.open.trade.service.trade.*;
import com.mdb.open.trade.utils.ConvertFileVoUtil;
import com.mdb.open.trade.utils.NumUtils;
import com.mdb.open.trade.validator.CheckMultiStatusValidator;
import com.mdb.user.LoginUserInfoHelper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * @author liuyi
 * @date 2019/06/29
 **/
@RestController
@RequestMapping("tf")
@Api(tags = "贸易金融数据提交")
@Log4j2
public class TradeResource extends SuperResources {

    @Autowired
    AttachFileService attachFileService;

    @Autowired
    TfMerchantBankAccountService tfMerchantBankAccountService;

    @Autowired
    TfTradeFileBasicInfoService tfTradeFileBasicInfoService;

    @Autowired
    TfTradeFileCustomsInfoService tfTradeFileCustomsInfoService;

    @Autowired
    TfTradeFileExtendInfoService tfTradeFileExtendInfoService;

    @Autowired
    TfTradeFileItemInfoService tfTradeFileItemInfoService;

    @Autowired
    TfTradeFileTransportInfoService tfTradeFileTransportInfoService;

    @Autowired
    TfLoanApplyBasicInfoService tfLoanApplyBasicInfoService;

    @Autowired
    TfLoanApplyBaseInfoService loanApplyBaseInfoService;

    @Autowired
    TfAttachFileService tfAttachFileService;

    @Autowired
    TfLoanApplyCustomsInfoService tfLoanApplyCustomsInfoService;

    @Autowired
    TradeFileFacade tradeFileFacade;

    @Autowired
    LoanApplyFlowFacade loanApplyFlowFacade;

    @Autowired
    TfInwardClaimService inwardClaimService;

    @Autowired
    ConvertFileVoUtil convertFileVoUtil;

    @Autowired
    CheckMultiStatusValidator checkMultiStatusValidator;

    @Autowired
    TfMerchantInfoService tfMerchantInfoService;

    @Autowired
    SequenceGenerator sequenceGenerator;

    @Autowired
    TradeOpenProperties tradeOpenProperties;

    @Autowired
    RiskTradeApplyProvider riskTradeApplyProvider;

    @Autowired
    LoginUserInfoHelper loginUserInfoHelper;

    @Autowired
    WorkOrderProducer workOrderProducer;

    @Autowired
    TfLoanContractService tfLoanContractService;

    @Autowired
    CustomerClient customerClient;

    @LogAnnotation
    @ApiOperation("test")
    @GetMapping("/getList")
    public ListResultEx<AttachFileVo> findByCondition() {
        List<AttachFile> attachFiles = attachFileService.list();
        System.out.println(JSON.toJSONString(attachFiles));
        return convertListResult(attachFiles, AttachFileVo.class);
    }

    @LogAnnotation
    @ApiOperation("提交融资申请")
    @PostMapping("/loan_apply")
    @DenyRepeatSubmit(type = RepeatSubmitTypeEnum.EXCLUSIVE_SUBMIT)
    public ResultEx<SubmitApplyResultVo> submitApply(@RequestBody WebLoanApplyDto loanApplyDto) {
        SubmitApplyResultVo vo = new SubmitApplyResultVo();
        String customerCode = loginUserInfoHelper.getCustomerCode(Boolean.TRUE);

        ResultEx<TradeFileBasicInfo> basicInfoEx = null;

        if (ObjectUtil.isNotEmpty(loanApplyDto.getTradeFileNo())) {
            basicInfoEx = tfTradeFileBasicInfoService.getInfoByNo(loanApplyDto.getTradeFileNo());
        } else if (ObjectUtil.isNotEmpty(loanApplyDto.getBusinessNo())) {
            basicInfoEx = tfTradeFileBasicInfoService.getInfoByBusinessNo(loanApplyDto.getBusinessNo());
        } else {
            return ResultEx.fail("融资档案编号或业务编号必填其一！");
        }

        if (basicInfoEx.isFailed() || ObjectUtil.isEmpty(basicInfoEx.getData())) {
            return ResultEx.makeResult(PlatformRetCodeEnum.APPLY_NOT_EXIST);
        }

        //校验资料是否完善
        if (TradeFileStatusEnum.TO_BE_ADDED.equals(basicInfoEx.getData().getStatus())) {
            return ResultEx.makeResult(PlatformRetCodeEnum.TRADE_FILE_UNCOMPLETED);
        }
        //校验资料是否完善
        if (!TradeFileApplyStatusEnum.INIT.equals(basicInfoEx.getData().getApplyStatus())) {
            return ResultEx.makeResult(PlatformRetCodeEnum.TRADE_FILE_STATUS_WRONG);
        }

        //获取报关信息
        ListResultEx<TradeFileCustomsInfo> customsEx = tfTradeFileCustomsInfoService.queryInfoByNo(loanApplyDto.getTradeFileNo());
        if (customsEx.isFailed() || ObjectUtil.isEmpty(customsEx.getData())) {
            return ResultEx.makeResult(PlatformRetCodeEnum.APPLY_NOT_EXIST);
        }

        List<String> customsNoList = Lists.newArrayList();

        for (TradeFileCustomsInfo info : customsEx.getData()) {
            if (!LocalDate.now().isBefore(info.getCommitTime().toLocalDate().plusDays(tradeOpenProperties.getCustomsDays()))) {
                return ResultEx.makeResult(PlatformRetCodeEnum.CUSTOMS_COMMIT_TIME_EXPIRED);
            }
            customsNoList.add(info.getCustomsNo());
        }

        //校验报关单是否已经提交过申请
        ResultEx cntCustomsEx = tfLoanApplyCustomsInfoService.cntCustoms(customsNoList);
        if (cntCustomsEx.isFailed()) {
            return ResultEx.fail(TradeWebErrorCodeEnum.CUSTOMS_NO_EXIST.getText());
        }

        //校验业务编号是否存在
        ResultEx bizCheckEx = tfLoanApplyBasicInfoService.checkBizNoIsExits(basicInfoEx.getData().getBusinessNo(), customerCode);
        if (bizCheckEx.isFailed()) {
            return bizCheckEx;
        }

        //调用客户中心判断客户状态
        Boolean merStatus = checkMultiStatusValidator.checkMerchantStatus(customerCode, basicInfoEx.getData().getMerchantNo());
        if (!merStatus) {
            return ResultEx.makeResult(PlatformRetCodeEnum.MERCHANT_STATUS_ILLEGAL);
        }
        //调用产品中心判断产品状态
        Boolean prodStatus = checkMultiStatusValidator.checkProductStatus(customerCode);
        if (!prodStatus) {
            return ResultEx.makeResult(PlatformRetCodeEnum.PRODUCT_STATUS_ILLEGAL);
        }

        // 附件非空校验
        QueryAttachListByNoListBo attachByTypeBo = new QueryAttachListByNoListBo();
        attachByTypeBo.setApplyOrderNo(basicInfoEx.getData().getTradeFileNo());
        attachByTypeBo.setStatus(AttachFileStatusEnum.NORMAL.getValue());
        List<AttachFile> fileList = tfAttachFileService.queryAttachByNoList(attachByTypeBo);

        List<AttachFileTypeEnum> enumList = AttachFileTypeEnum.findByGroup(FileGroupTypeEnum.APPLY_ORDER, false);
        Map<AttachFileTypeEnum, List<AttachFile>> listMap =
                fileList.stream().collect(Collectors.groupingBy(AttachFile::getType));
        for (Map.Entry<AttachFileTypeEnum, List<AttachFile>> entry : listMap.entrySet()) {
            enumList.remove(entry.getKey());
        }
        if (ObjectUtil.isNotEmpty(enumList)) {
            StringBuilder returnMessage = new StringBuilder();
            for (AttachFileTypeEnum typeEnum : enumList) {
                returnMessage.append(typeEnum.getText()).append("不能为空").append(";");
            }
            return ResultEx.fail(returnMessage.toString());
        }

        BigDecimal baseAmount = BigDecimal.ZERO;
        if (basicInfoEx.getData().getContractAmount().compareTo(basicInfoEx.getData().getCustomsAmount()) > 0) {
            baseAmount = basicInfoEx.getData().getCustomsAmount();
        } else {
            baseAmount = basicInfoEx.getData().getContractAmount();
        }

        LoanApplyBo loanApplyBo = new LoanApplyBo();
        if (ObjectUtil.isEmpty(loanApplyDto.getAccUniqueNo())) {

            if (ObjectUtil.isEmpty(loanApplyDto.getAccNameCn()) || ObjectUtil.isEmpty(loanApplyDto.getAccNameEn()) ||
                    ObjectUtil.isEmpty(loanApplyDto.getAccNo()) || ObjectUtil.isEmpty(loanApplyDto.getSwiftCode())) {
                return ResultEx.fail("银行账号资料不全");
            }

            ResultEx<MerchantInfo> merchantEx = tfMerchantInfoService.getMerchantInfo(customerCode, basicInfoEx.getData().getMerchantNo());
            if (merchantEx.isFailed() || ObjectUtil.isEmpty(merchantEx.getData())) {
                return ResultEx.fail();
            }

            GetMerBankAccByDetailBo accByDetailBo = new GetMerBankAccByDetailBo();
            accByDetailBo.setCustomerCode(customerCode);
            accByDetailBo.setCustomerName(merchantEx.getData().getCustomerName());
            accByDetailBo.setMerchantNo(basicInfoEx.getData().getMerchantNo());
            accByDetailBo.setMerchantName(basicInfoEx.getData().getMerchantName());
            accByDetailBo.setMerchantType(merchantEx.getData().getMerchantType());
            accByDetailBo.setMerchantIdNo(merchantEx.getData().getMerchantCertNumber());
            accByDetailBo.setAccCnName(loanApplyDto.getAccNameCn());
            accByDetailBo.setAccEnName(loanApplyDto.getAccNameEn());
            accByDetailBo.setReceiveAddressEn(loanApplyDto.getAddressEn());
            accByDetailBo.setAccNo(loanApplyDto.getAccNo());
            accByDetailBo.setRecevSwiftCode(loanApplyDto.getSwiftCode());
//            accByDetailBo.setIntermediarySwiftCode(loanApplyDto.getIntermediarySwiftCode());

            ResultEx<MerchantBankAccount> accountResultEx = tfMerchantBankAccountService.getMerBankAccByDetail(accByDetailBo);
            if (accountResultEx.isFailed()) {
                return ResultEx.makeResult(accountResultEx.getRetCode(), accountResultEx.getRetMsg());
            }

            loanApplyBo.setAccUniqueNo(accountResultEx.getData().getAccUniqueNo());
            vo.setAccUniqueNo(accountResultEx.getData().getAccUniqueNo());


        } else {
            loanApplyBo.setAccUniqueNo(loanApplyDto.getAccUniqueNo());
            vo.setAccUniqueNo(loanApplyDto.getAccUniqueNo());
        }

        loanApplyBo.setMerchantNo(basicInfoEx.getData().getMerchantNo());
        loanApplyBo.setTradeFileNo(loanApplyDto.getTradeFileNo());
        loanApplyBo.setBusinessNo(basicInfoEx.getData().getBusinessNo());
        loanApplyBo.setMerchantName(basicInfoEx.getData().getMerchantName());
        loanApplyBo.setBasicInfo(basicInfoEx.getData());
        loanApplyBo.setCustomsInfoList(customsEx.getData());
        loanApplyBo.setCustomerCode(customerCode);
        loanApplyBo.setBaseAmount(baseAmount);
        loanApplyBo.setCustomsTotalAmount(basicInfoEx.getData().getItemsAmount());
        loanApplyBo.setCcy("USD");

        //创建融资申请单（查出已提交的融资档案，插入对应融资申请相关表）
        ResultEx<SubmitApplyResultVo> resultEx = loanApplyFlowFacade.createApplyOrder(loanApplyBo);
        if (resultEx.isFailed()) {
            return resultEx;
        }

        //提交融资申请
        String applyOrderNo = resultEx.getData().getApplyOrderNo();
        vo.setApplyOrderNo(applyOrderNo);
        vo.setFinanceAmount(resultEx.getData().getFinanceAmount());
        vo.setExpectedAmount(resultEx.getData().getExpectedAmount());
        vo.setCcy(resultEx.getData().getCcy());

        TradeCallAmlBo tradeCallAmlBo = new TradeCallAmlBo();
        tradeCallAmlBo.setApplyOrderNo(resultEx.getData().getApplyOrderNo());
//        tradeCallAmlBo.setCargoDtoList(resultEx.getData().getCargoDtoList());
//        tradeCallAmlBo.setBlacklistScanListDtos(resultEx.getData().getBlacklistScanListDtos());

        //工单-业务人员审批
        WorkOrderCreateDto workOrderCreateDto = new WorkOrderCreateDto();
        workOrderCreateDto.setWorkOrderType(OrderTypeEnum.FINANCIAL_APPLY_MANAGER_APPROVE);
        workOrderCreateDto.setProductCode(ProductCodeEnum.TF01);
        workOrderCreateDto.setCustomerNo(loginUserInfoHelper.getCustomerCode());
        workOrderCreateDto.setCustomerName(loginUserInfoHelper.getLoginInfo().getUserName());
        workOrderCreateDto.setBusinessNo(applyOrderNo);
        workOrderCreateDto.setMerchantName(basicInfoEx.getData().getMerchantName());
        workOrderCreateDto.setMerchantNo(basicInfoEx.getData().getMerchantNo());
        workOrderCreateDto.setAdditionData(new FinancialServiceApply().setMerchantNo(basicInfoEx.getData().getMerchantNo()));

        log.info("====================> 开始异步调用创建工单的请求");
        CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() {
                try {
                    workOrderProducer.create(workOrderCreateDto);
//                    startAml(tradeCallAmlBo);
                } catch (Exception e) {
                    log.error("=========>调用工单系统创建工单报错，申请单号：{},异常信息：{}", applyOrderNo, e.getMessage());
                }
            }
        });

        return ResultEx.ok(vo);
    }

//    @Async
//    @Retryable(value = Exception.class, maxAttempts = 20, backoff = @Backoff(delay = 10000, multiplier = 2))
//    public void startAml(TradeCallAmlBo bo) {
//        ResultEx amlEx = loanApplyFlowFacade.tradeCallAml(bo);
//        amlEx.assertSuccess();
//    }
//
//    @Recover
//    public void startRiskRecover(Exception e, TradeCallAmlBo bo) {
//        log.error("调用风控模型失败, param:{}", JSON.toJSONString(bo), e);
//    }

    @LogAnnotation
    @ApiOperation("融资档案提交")
    @PostMapping("/trade/upload_resource")
    @DenyRepeatSubmit(type = RepeatSubmitTypeEnum.EXCLUSIVE_SUBMIT)
    public ResultEx<SaveTradeFileVo> submit(@RequestBody TradeFileSaveDto submitDto) {

        //非空校验
        // 1、进口方英文名或中文名至少填一项
        if (ObjectUtil.isEmpty(submitDto.getTradeFileBasicInfoDto().getImporterCnName()) &&
                ObjectUtil.isEmpty(submitDto.getTradeFileBasicInfoDto().getImporterEnName())) {

            return ResultEx.makeResult(PlatformRetCodeEnum.IMPORTER_CN_EN_NAME_MUST_EXIST_ONE);
        }

        // 2、收货人英文名或中文名至少填一项
        if (ObjectUtil.isEmpty(submitDto.getTradeFileBasicInfoDto().getImporterCnName()) &&
                ObjectUtil.isEmpty(submitDto.getTradeFileBasicInfoDto().getImporterEnName())) {

            return ResultEx.makeResult(PlatformRetCodeEnum.RECEIVER_CN_EN_NAME_MUST_EXIST_ONE);
        }

        boolean exportFileFlag = false;
        int exportFileSize = 0;

        // 3、附件非空校验
        List<AttachFileTypeEnum> enumList = AttachFileTypeEnum.findByGroup(FileGroupTypeEnum.APPLY_ORDER, false);
        Map<AttachFileTypeEnum, List<TradeFileAttachDto>> listMap =
                submitDto.getTradeFileAttachDtoList().stream().collect(Collectors.groupingBy(TradeFileAttachDto::getFileType));
        for (Map.Entry<AttachFileTypeEnum, List<TradeFileAttachDto>> entry : listMap.entrySet()) {
            enumList.remove(entry.getKey());
            if (AttachFileTypeEnum.EXPORTED_VERIFICATION_SLIP.equals(entry.getKey())) {
                exportFileFlag = true;
                exportFileSize = entry.getValue().size();
            }
        }
        if (ObjectUtil.isNotEmpty(enumList)) {
            StringBuilder returnMessage = new StringBuilder();
            for (AttachFileTypeEnum typeEnum : enumList) {
                returnMessage.append(typeEnum.getText()).append("不能为空").append(";");
            }
            return ResultEx.fail(returnMessage.toString());
        }

        String customerCode = loginUserInfoHelper.getCustomerCode(true);

        if (ObjectUtil.isEmpty(submitDto.getTradeFileBasicInfoDto())) {
            return ResultEx.fail();
        }

        TradeFileTempSaveBo bo = new TradeFileTempSaveBo();

        TradeFileTempBasicInfoBo basicInfoBo = new TradeFileTempBasicInfoBo();
        basicInfoBo.setCustomerCode(customerCode);
        if (ObjectUtil.isEmpty(submitDto.getTradeFileBasicInfoDto().getTradeFileNo())) {
            //校验业务编号是否存在
            ResultEx bizCheckEx = tfTradeFileBasicInfoService.checkBizNoIsExits(submitDto.getTradeFileBasicInfoDto().getBusinessNo(),
                    customerCode);
            if(bizCheckEx.isFailed()){
                return bizCheckEx;
            }
            //客户名称
            ResultEx<CustBaseInfoVo> cusInfo = customerClient.getRelationCustomerInfoByParentCode(customerCode, RelationTypeEnum.BIZ_SUBJECT_COMPANY);
            if (cusInfo.isFailed()) {
                return ResultEx.makeResult(cusInfo);
            }
            if(ObjectUtil.isEmpty(cusInfo.getData())){
                return ResultEx.fail(TradeWebErrorCodeEnum.CUSTOMER_QUERY_EMPTY.getText());
            }
            basicInfoBo.setCustomerName(cusInfo.getData().getName());

        }

        ResultEx<MerchantInfo> merchantInfoEx = tfMerchantInfoService.getMerchantInfo(customerCode, submitDto.getTradeFileBasicInfoDto().getMerchantNo());
        if (merchantInfoEx.isFailed() || ObjectUtil.isEmpty(merchantInfoEx.getData())) {
            return ResultEx.fail(TradeWebErrorCodeEnum.CUSTOMER_QUERY_EMPTY.getText());
        }

        basicInfoBo.setTradeFileNo(submitDto.getTradeFileBasicInfoDto().getTradeFileNo());
        basicInfoBo.setMcustomerCode(merchantInfoEx.getData().getMcustomerCode());
        basicInfoBo.setMerchantNo(submitDto.getTradeFileBasicInfoDto().getMerchantNo());
        basicInfoBo.setMerchantName(merchantInfoEx.getData().getMerchantName());
        basicInfoBo.setBusinessNo(submitDto.getTradeFileBasicInfoDto().getBusinessNo());
        basicInfoBo.setBusinessType(submitDto.getTradeFileBasicInfoDto().getBusinessType());
        basicInfoBo.setImporterCnName(submitDto.getTradeFileBasicInfoDto().getImporterCnName());
        basicInfoBo.setImporterEnName(submitDto.getTradeFileBasicInfoDto().getImporterEnName());
        basicInfoBo.setImporterAddress(submitDto.getTradeFileBasicInfoDto().getImporterAddress());
        basicInfoBo.setContractAmount(NumUtils.toBigDecimalToNull(submitDto.getTradeFileBasicInfoDto().getContractAmount()));
        basicInfoBo.setContractCcy(submitDto.getTradeFileBasicInfoDto().getContractCcy());
        basicInfoBo.setSourceType(TradeSourceTypeEnum.API);
        basicInfoBo.setStatus(TradeFileStatusEnum.COMPLETED);
        basicInfoBo.setApplyStatus(TradeFileApplyStatusEnum.INIT);
        if (exportFileFlag) {
            if (tradeOpenProperties.getExportFileSize() < exportFileSize) {
                basicInfoBo.setExportVeriStatus(LoanApplyExportFileStatusEnum.UPLOAD_PART);
            } else {
                basicInfoBo.setExportVeriStatus(LoanApplyExportFileStatusEnum.UPLOAD_COMPLETED);
            }
        } else {
            basicInfoBo.setExportVeriStatus(LoanApplyExportFileStatusEnum.UN_UPLOAD);
        }

        BigDecimal itemAmount = BigDecimal.ZERO;
        BigDecimal customsAmount = BigDecimal.ZERO;
        LocalDateTime customsTime = null;
        int customsCnt = 0;
        if (ObjectUtil.isNotEmpty(submitDto.getTradeFileCustomsListDtoList())) {
            List<TradeFileTempCustomsListBo> customsInfoBoList = Lists.newArrayList();
            customsCnt = submitDto.getTradeFileCustomsListDtoList().size();
            Map<String, String> uniqueMap = Maps.newHashMap();
            for (TradeFileCustomsListDto customsListDto : submitDto.getTradeFileCustomsListDtoList()) {
                TradeFileTempCustomsListBo customsListBo = new TradeFileTempCustomsListBo();
                if (ObjectUtil.isEmpty(customsListDto.getTradeFileTempCustomsInfoDto()) || ObjectUtil.isEmpty(customsListDto.getTradeFileTempCustomsInfoDto().getCustomsNo())) {
                    return ResultEx.fail(TradeWebErrorCodeEnum.CUSTOMS_NO_MUST_INPUT.getText());
                }

                //报关信息
                if (ObjectUtil.isNotEmpty(customsListDto.getTradeFileTempCustomsInfoDto())) {
                    if (uniqueMap.containsKey(customsListDto.getTradeFileTempCustomsInfoDto().getCustomsNo())) {
                        return ResultEx.fail(TradeWebErrorCodeEnum.CUSTOMS_NO_DUPLICATE.getText());
                    }
                    uniqueMap.put(customsListDto.getTradeFileTempCustomsInfoDto().getCustomsNo(), customsListDto.getTradeFileTempCustomsInfoDto().getCustomsNo());
                    TradeFileTempCustomsInfoBo customsInfoBo = new TradeFileTempCustomsInfoBo();
                    customsInfoBo.setTradeFileCustomsNo(customsListDto.getTradeFileTempCustomsInfoDto().getTradeFileCustomsNo());
                    customsInfoBo.setCustomsNo(customsListDto.getTradeFileTempCustomsInfoDto().getCustomsNo());
                    customsInfoBo.setCustomsLocation(customsListDto.getTradeFileTempCustomsInfoDto().getCustomsLocation());
                    customsInfoBo.setCustomsTitle(customsListDto.getTradeFileTempCustomsInfoDto().getCustomsTitle());
                    customsInfoBo.setCustomsAmount(NumUtils.toBigDecimalToNull(customsListDto.getTradeFileTempCustomsInfoDto().getCustomsAmount()));
                    customsInfoBo.setCcy(customsListDto.getTradeFileTempCustomsInfoDto().getCcy());
                    customsInfoBo.setCommitTime(customsListDto.getTradeFileTempCustomsInfoDto().getCommitTime());
                    customsInfoBo.setLoadingPort(customsListDto.getTradeFileTempCustomsInfoDto().getLoadingPort());
                    customsInfoBo.setLoadingPortCode(customsListDto.getTradeFileTempCustomsInfoDto().getLoadingPortCode());
                    customsInfoBo.setDestinPort(customsListDto.getTradeFileTempCustomsInfoDto().getDestinPort());
                    customsInfoBo.setDestinPortCode(customsListDto.getTradeFileTempCustomsInfoDto().getDestinPortCode());
                    customsInfoBo.setDestinCountry(customsListDto.getTradeFileTempCustomsInfoDto().getDestinCountry());
                    customsListBo.setTradeFileTempCustomsInfoBo(customsInfoBo);
                    customsAmount = customsAmount.add(customsInfoBo.getCustomsAmount());
                    if (customsTime == null) {
                        customsTime = customsInfoBo.getCommitTime();
                    } else {
                        customsTime = customsTime.isAfter(customsInfoBo.getCommitTime()) ? customsInfoBo.getCommitTime() : customsTime;
                    }
                }

                //运输信息
                if (ObjectUtil.isNotEmpty(customsListDto.getTradeFileTempTransportInfoDto())) {
                    TradeFileTempTransportInfoBo transportInfoBo = new TradeFileTempTransportInfoBo();
                    transportInfoBo.setCustomsNo(customsListDto.getTradeFileTempTransportInfoDto().getCustomsNo());
                    transportInfoBo.setLadingBillNo(customsListDto.getTradeFileTempTransportInfoDto().getLadingBillNo());
                    transportInfoBo.setContainerNo(customsListDto.getTradeFileTempTransportInfoDto().getContainerNo());
                    transportInfoBo.setShipper(customsListDto.getTradeFileTempTransportInfoDto().getShipper());
                    transportInfoBo.setReceiverCnName(customsListDto.getTradeFileTempTransportInfoDto().getReceiverCnName());
                    transportInfoBo.setReceiverEnName(customsListDto.getTradeFileTempTransportInfoDto().getReceiverEnName());
                    transportInfoBo.setShipLoadTime(customsListDto.getTradeFileTempTransportInfoDto().getShipLoadTime());
                    transportInfoBo.setReceiverCountry(customsListDto.getTradeFileTempTransportInfoDto().getReceiverCountry());
                    transportInfoBo.setTransportName(customsListDto.getTradeFileTempTransportInfoDto().getTransportName());
                    transportInfoBo.setTransportType(customsListDto.getTradeFileTempTransportInfoDto().getTransportType());
                    customsListBo.setTradeFileTempTransportInfoBo(transportInfoBo);

                }

                //商品信息
                if (ObjectUtil.isNotEmpty(customsListDto.getTradeFileTempItemInfoDtoList())) {
                    List<TradeFileTempItemInfoBo> itemInfoBoList = Lists.newArrayList();
                    for (TradeFileItemInfoDto dto : customsListDto.getTradeFileTempItemInfoDtoList()) {
                        TradeFileTempItemInfoBo itemInfoBo = new TradeFileTempItemInfoBo();
                        itemInfoBo.setCustomsNo(dto.getCustomsNo());
                        itemInfoBo.setTradeFileItemNo(dto.getTradeFileItemNo());
                        itemInfoBo.setItemCnName(dto.getItemCnName());
                        itemInfoBo.setItemEnName(dto.getItemEnName());
                        itemInfoBo.setHsCode(dto.getHsCode());
                        itemInfoBo.setBrand(dto.getBrand());
                        itemInfoBo.setUnit(dto.getUnit());
                        itemInfoBo.setQuantity(NumUtils.toBigDecimalToNull(dto.getQuantity()));
                        itemInfoBo.setCustomUnitAmount(NumUtils.toBigDecimalToNull(dto.getCustomUnitAmount()));
                        itemInfoBo.setCustomUnitCcy(dto.getCustomUnitCcy());
                        itemInfoBo.setCustomTotalAmount(NumUtils.toBigDecimalToNull(dto.getCustomTotalAmount()));
                        itemInfoBo.setCustomTotalCcy(dto.getCustomTotalCcy());
                        if (NumberUtil.isGreater(NumUtils.toBigDecimal(dto.getCustomUnitAmount()), NumUtils.toBigDecimal(dto.getCustomTotalAmount()))) {
                            return ResultEx.fail(TradeWebErrorCodeEnum.ITEM_AMOUNT_ILLEGAL.getText());
                        }
                        itemInfoBoList.add(itemInfoBo);
                        itemAmount = itemAmount.add(itemInfoBo.getCustomTotalAmount());

                    }
                    customsListBo.setTradeFileTempItemInfoBoList(itemInfoBoList);

                }
                customsInfoBoList.add(customsListBo);
            }
            bo.setTradeFileTempCustomsListBoList(customsInfoBoList);
        }

        if (ObjectUtil.isNotEmpty(submitDto.getTradeFileTempExtendInfoDto())) {
            TradeFileTempExtendInfoBo extendInfoBo = new TradeFileTempExtendInfoBo();
            extendInfoBo.setDepositAmount(NumUtils.toBigDecimalToNull(submitDto.getTradeFileTempExtendInfoDto().getDepositAmount()));
            extendInfoBo.setDepositCcy(submitDto.getTradeFileTempExtendInfoDto().getDepositCcy());
            extendInfoBo.setDepositPercent(NumUtils.toBigDecimalToNull(submitDto.getTradeFileTempExtendInfoDto().getDepositPercent()));
            extendInfoBo.setInsuranceAmount(NumUtils.toBigDecimalToNull(submitDto.getTradeFileTempExtendInfoDto().getInsuranceAmount()));
            extendInfoBo.setInsuranceCcy(submitDto.getTradeFileTempExtendInfoDto().getInsuranceCcy());
            extendInfoBo.setInsurancePercent(NumUtils.toBigDecimalToNull(submitDto.getTradeFileTempExtendInfoDto().getInsurancePercent()));
            bo.setTradeFileTempExtendInfoBo(extendInfoBo);
        }
        if (ObjectUtil.isNotEmpty(submitDto.getTradeFileAttachDtoList())) {

            List<AttachFile> insertList = Lists.newArrayList();
            List<String> removeList = Lists.newArrayList();
            for (TradeFileAttachDto attachDto : submitDto.getTradeFileAttachDtoList()) {
                AttachFile insertAttach = new AttachFile();
                insertAttach.setAttachNo(sequenceGenerator.generator(TfSequenceEnum.ATTACH_NO));
                insertAttach.setCustomerCode(customerCode);
                insertAttach.setFileName(attachDto.getFileName());
                insertAttach.setMerchantNo(basicInfoBo.getMerchantNo());
                insertAttach.setType(attachDto.getFileType());
                insertAttach.setFileUrl(attachDto.getFileNo());
                insertAttach.setStatus(AttachFileStatusEnum.NORMAL);
                insertList.add(insertAttach);
            }

            if (ObjectUtil.isNotEmpty(insertList)) {
                bo.setInsertList(insertList);
            }
            if (ObjectUtil.isNotEmpty(removeList)) {
                bo.setRemoveList(removeList);
            }
        }

        basicInfoBo.setCustomsAmount(customsAmount);
        basicInfoBo.setItemsAmount(itemAmount);
        basicInfoBo.setCustomsCnt(customsCnt);
        basicInfoBo.setCustomsTime(customsTime);
        bo.setTradeFileTempBasicInfoBo(basicInfoBo);

        ResultEx<TradeFileBasicInfo> saveEx= tradeFileFacade.tempSaveTradeFile(bo);
        if (saveEx.isFailed()) {
            return ResultEx.makeResult(saveEx.getRetCode(), saveEx.getRetMsg());
        }

        //推送风控mq
        RiskProviderMo riskProviderMo = new RiskProviderMo();
        riskProviderMo.setPcustomerCode(customerCode);
        riskProviderMo.setCustomerCode(basicInfoBo.getMcustomerCode());

        log.info("====================> 开始异步通知风控");
        CompletableFuture.runAsync(new Runnable() {
            @Override
            public void run() {
                try {
                    ResultEx<Integer> resultEx = tfTradeFileBasicInfoService.cntCompletedTradeFile(customerCode, basicInfoBo.getMerchantNo());
                    resultEx.assertSuccess();

                    if (resultEx.getData() == 3) {
                        StartRiskModelDto riskModelDto = new StartRiskModelDto();
                        riskModelDto.setBusinessKey(customerCode);
                        riskModelDto.setModelType(ModelTypeEnum.TF_MERCHANT_CALCULATE_AMOUNT);
                        riskModelDto.setProductCode(ProductCodeEnum.TF01);
                        riskModelDto.setCustomerCode(basicInfoBo.getMcustomerCode());
                        riskModelDto.setPcustomerCode(customerCode);
                        riskModelDto.setRemark("贸易达到三笔, 商户核额");
                        log.info("贸易达到三笔, 商户核额,:{}", riskModelDto);

                        tradeFileFacade.startRisk(riskModelDto);
                    }
                    riskTradeApplyProvider.send(riskProviderMo);
                } catch (Exception e) {
                    log.error("=========>异步通知风控报错，客户号：{},商户号:{},异常信息：{}", customerCode, basicInfoBo.getMerchantNo(), e.getMessage());
                }
            }
        });

        SaveTradeFileVo vo = new SaveTradeFileVo();
        vo.setTradeFileNo(saveEx.getData().getTradeFileNo());
        vo.setBusinessNo(saveEx.getData().getBusinessNo());

        return ResultEx.ok(vo);
    }

    @LogAnnotation
    @ApiOperation("融资申请记录")
    @GetMapping("apply/page_list")
    public ListResultEx<LoanApplyBaseInfoPageVo> selectLoanApplyRejectPage(@ModelAttribute LoanApplyPageQueryDto dto) {
        LoanApplyQueryBo bo = new LoanApplyQueryBo();
        bo.setMerchantName(dto.getMerchantName());
        bo.setCustomerCode(loginUserInfoHelper.getCustomerCode(true));
        bo.setApplyOrderNo(dto.getApplyOrderNo());
        bo.setBusinessNo(dto.getBusinessNo());
        bo.setPageNo(dto.getPageNo());
        bo.setPageSize(dto.getPageSize());
        bo.setSort(dto.getSort());
        bo.setOrder(dto.getOrder());
        bo.setStartDate(dto.getStartDate());
        bo.setEndDate(dto.getEndDate());

        if (ObjectUtil.isEmpty(dto.getSort())) {
            bo.setSort(Fields.ID);
            bo.setOrder(OrderByEnum.DESC);
        }

        IPage<LoanApplyBaseInfo> pageList = loanApplyBaseInfoService.pageQuery(bo);
        List<LoanApplyBaseInfoPageVo> voList = Lists.newArrayList();
        if (ObjectUtil.isNotEmpty(pageList.getRecords())) {

            List<String> applyOrderList = pageList.getRecords().stream().map(LoanApplyBaseInfo::getApplyOrderNo).collect(Collectors.toList());
            List<LoanContract> loanContracts = tfLoanContractService.queryLoanContractList(applyOrderList);
            Map<String, LoanContract> contractMap = Maps.newHashMap();
            if (ObjectUtil.isNotEmpty(loanContracts)) {
                contractMap = loanContracts.stream().collect(Collectors.toMap(LoanContract::getApplyOrderNo, e -> e));
            }

            for (LoanApplyBaseInfo info : pageList.getRecords()) {
                LoanApplyBaseInfoPageVo vo = new LoanApplyBaseInfoPageVo();
                vo.setCustomerCode(info.getCustomerCode());
                vo.setMerchantName(info.getMerchantName());
                vo.setApplyOrderNo(info.getApplyOrderNo());
                vo.setFinanceAmount(info.getFinanceAmount());
                vo.setExpectedAmount(info.getExpectedAmount());
                vo.setApproveAmount(contractMap.get(info.getApplyOrderNo()) == null ? null : contractMap.get(info.getApplyOrderNo()).getApproveAmount());
                vo.setCcy(info.getCcy());
                vo.setApplyStatus(info.getApplyStatus());
                vo.setApplyTime(info.getApplyTime());
                voList.add(vo);
            }

        }

        return ListResultEx.ok(voList, pageList.getTotal(), pageList.getCurrent(), pageList.getSize());

    }

    @LogAnnotation
    @ApiOperation("融资申请详情")
    @GetMapping("apply/info")
    public ResultEx<LoanApplyBaseInfoVo> getLoanApplyInfo(@ModelAttribute LoanApplyQueryDto dto) {
        LoanApplyQueryBo bo = new LoanApplyQueryBo();
        bo.setCustomerCode(loginUserInfoHelper.getCustomerCode(true));
        bo.setApplyOrderNo(dto.getApplyOrderNo());
        bo.setBusinessNo(dto.getBusinessNo());
        bo.setTradeFileNo(dto.getTradeFileNo());

        ResultEx<LoanApplyBaseInfo> infoResultEx = loanApplyBaseInfoService.getApplyBaseInfo(bo);
        if (infoResultEx.isFailed() || ObjectUtil.isEmpty(infoResultEx.getData())) {
            return ResultEx.fail(TradeWebErrorCodeEnum.APPLY_NOT_EXIST.getText());
        }

        ResultEx<LoanContract> loanEx = tfLoanContractService.findByApplyNo(infoResultEx.getData().getApplyOrderNo());
        LoanContract contract = null;
        if (loanEx.isSuccess() && ObjectUtil.isNotEmpty(loanEx.getData())) {
            contract = loanEx.getData();
        }


        LoanApplyBaseInfo info = infoResultEx.getData();

        LoanApplyBaseInfoVo vo = new LoanApplyBaseInfoVo();
        vo.setCustomerCode(info.getCustomerCode());
        vo.setCustomerName(info.getCustomerName());
        vo.setMerchantNo(info.getMerchantNo());
        vo.setMerchantName(info.getMerchantName());
        vo.setPlatformAcc(info.getPlatformAcc());
        vo.setApplyOrderNo(info.getApplyOrderNo());
        vo.setTradeFileNo(info.getTradeFileNo());
        vo.setBusinessNo(info.getBusinessNo());
        vo.setFinanceAmount(info.getFinanceAmount());
        vo.setExpectedAmount(info.getExpectedAmount());
        vo.setApproveAmount(contract == null ? null : contract.getApproveAmount());
        vo.setCcy(info.getCcy());
        vo.setReceiveAccCnName(info.getReceiveAccCnName());
        vo.setReceiveAccEnName(info.getReceiveAccEnName());
        vo.setReceiveAddress(info.getReceiveAddress());
        vo.setReceiveAccNo(info.getReceiveAccNo());
        vo.setReceiveAccBranch(info.getReceiveAccBranch());
        vo.setSwiftCode(info.getSwiftCode());
        vo.setApplyStatus(info.getApplyStatus());
        vo.setApplyTime(info.getApplyTime());

        return ResultEx.ok(vo);
    }

    @LogAnnotation
    @ApiOperation("更新收款账号信息")
    @PostMapping("/bank_acc/update")
    public ResultEx updateMerchantAccount(@RequestBody MerchantBankAccountUpdateDto dto) {

        String customerCode = loginUserInfoHelper.getCustomerCode(true);
        ResultEx<MerchantBankAccount> resultEx = tfMerchantBankAccountService.getAccountInfoByAccUniNo(dto.getAccUniNo(), customerCode);
        if (resultEx.isFailed() || ObjectUtil.isEmpty(resultEx.getData())) {
            return ResultEx.fail("收款账号信息不存在");
        }
        MerchantBankAccount oldAccount = resultEx.getData();

        //校验新编辑的收款账号是否重复
        QueryMerchantBankAccountDto accountDto = new QueryMerchantBankAccountDto();
        accountDto.setCustomerCode(customerCode);
        accountDto.setMerchantNo(oldAccount.getMerchantNo());
        List<MerchantBankAccount> accountList = tfMerchantBankAccountService.queryMerchantAccountListByMerNo(accountDto).getData();
        List<String> accList = Lists.newArrayList();
        if(ObjectUtil.isNotEmpty(accountList) && accountList.size() > 0){
            accList = accountList.stream().map(MerchantBankAccount::getAccNo).collect(Collectors.toList());
        }

        //当前商户，新编辑的收款账号若不为原账号且已存在
        if (accList.contains(dto.getAccNo())
                && !dto.getAccNo().equals(resultEx.getData().getAccNo())) {
            return ResultEx.makeResult(PlatformRetCodeEnum.ACCOUNT_REPEAT);
        }

        oldAccount.setAccCnName(dto.getAccCnName());
        oldAccount.setAccEnName(dto.getAccEnName());
        oldAccount.setAccNo(dto.getAccNo());
        oldAccount.setReceiveAddressCn(dto.getReceiveAddressCn());
        oldAccount.setReceiveAddressEn(dto.getReceiveAddressEn());
        oldAccount.setRecevSwiftCode(dto.getRecevSwiftCode());
        oldAccount.setIntermediarySwiftCode(dto.getIntermediarySwiftCode());
        oldAccount.setAccBranch(dto.getAccBranch());
        oldAccount.setDefaultType(dto.getDefaultType());

        ResultEx result = tfMerchantBankAccountService.updateMerchantAccount(oldAccount);
        if (result.isFailed()) {
            return ResultEx.makeResult(PlatformRetCodeEnum.UPDATE_ACCOUNT_FAIL);
        }

        return ResultEx.ok();
    }

    @LogAnnotation
    @ApiOperation("新增单个商户收款账号")
    @PostMapping("/bank_acc/save")
    public ResultEx<SaveMerchantBankAccountVo> saveAcc(@RequestBody AddMerchantBankAccountDto dto) {

        String customerCode = loginUserInfoHelper.getCustomerCode(true);
        //客户名称
        ResultEx<MerchantInfo> cusInfoEx = tfMerchantInfoService.getCustomerInfo(customerCode);
        if (cusInfoEx.isFailed()) {
            return ResultEx.makeResult(cusInfoEx.getRetCode(), cusInfoEx.getRetMsg());
        }
        if (ObjectUtil.isEmpty(cusInfoEx.getData())) {
            return ResultEx.fail(TradeWebErrorCodeEnum.CUSTOMER_QUERY_EMPTY.getText());
        }
        String cusName = cusInfoEx.getData().getCustomerName();

        ResultEx<MerchantInfo> merchantInfoEx = tfMerchantInfoService.getMerchantInfo(customerCode, dto.getMerchantNo());
        if (merchantInfoEx.isFailed() || ObjectUtil.isEmpty(merchantInfoEx.getData())) {
            return ResultEx.fail(TradeWebErrorCodeEnum.UPDATE_ACCOUNT_FAIL.getText());
        }

        //判断收款账号数是否达到上限
        String merchantNo = dto.getMerchantNo();

        int count = tfMerchantBankAccountService.countByMerchantNo(customerCode, merchantNo, BankAccountRecordStatusEnum.ENABLE);

        boolean setDefaultFlag = false;

        if (count == 0) {
            setDefaultFlag = true;
        }

        if (Boolean.TRUE.equals(count >= tradeOpenProperties.getAccountCount())) {
            return ResultEx.fail(TradeWebErrorCodeEnum.ACCOUNT_COUNT_OVER.getText());
        }
        //校验批量新增的收款账号是否重复（包括新增待插入的记录）
        int cnt = tfMerchantBankAccountService.countByMerchantNo(dto.getMerchantNo(), dto.getAccNo(), customerCode);
        if (cnt > 0) {
            return ResultEx.fail(TradeWebErrorCodeEnum.ACCOUNT_REPEAT.getText());
        }

        MerchantBankAccount merchantBankAccount = new MerchantBankAccount();
        merchantBankAccount.setDefaultType(MerBankAccDefaultTypeEnum.NORMAL);

        if (setDefaultFlag) {
            merchantBankAccount.setDefaultType(MerBankAccDefaultTypeEnum.DEFAULT);
        }
        merchantBankAccount.setAccUniqueNo(sequenceGenerator.generator(TfSequenceEnum.MERCHANT_BANK_ACC_UNIQUE_NO.setDataChannelEnum(DataChannelEnum.API)));
        merchantBankAccount.setCustomerCode(customerCode);
        merchantBankAccount.setStatus(BankAccountRecordStatusEnum.ENABLE);
        merchantBankAccount.setCustomerName(cusName);
        merchantBankAccount.setMerchantNo(dto.getMerchantNo());
        merchantBankAccount.setMcustomerCode(merchantInfoEx.getData().getMcustomerCode());
        merchantBankAccount.setMerchantName(merchantInfoEx.getData().getMerchantName());
        merchantBankAccount.setMerchantType(merchantInfoEx.getData().getMerchantType());
        merchantBankAccount.setMerchantIdNo(merchantInfoEx.getData().getMerchantCertNumber());
        merchantBankAccount.setReceiveAddressCn(dto.getReceiveAddressCn());
        merchantBankAccount.setReceiveAddressEn(dto.getReceiveAddressEn());
        merchantBankAccount.setRecevSwiftCode(dto.getRecevSwiftCode());
        merchantBankAccount.setIntermediarySwiftCode(dto.getIntermediarySwiftCode());
        merchantBankAccount.setAccCnName(merchantInfoEx.getData().getMerchantNameCn());
        merchantBankAccount.setAccNo(dto.getAccNo());
        merchantBankAccount.setAccEnName(merchantInfoEx.getData().getMerchantNameEn());
        merchantBankAccount.setAccBranch(dto.getAccBranch());

        boolean result = tfMerchantBankAccountService.save(merchantBankAccount);
        if(Boolean.FALSE.equals(result)) {
            return ResultEx.fail();
        }


        if (MerBankAccDefaultTypeEnum.DEFAULT.equals(dto.getDefaultType()) && !setDefaultFlag) {
            SetDefaultMerBankAccBo defaultMerBankAccBo = new SetDefaultMerBankAccBo();
            defaultMerBankAccBo.setAccUniqueNo(merchantBankAccount.getAccUniqueNo());
            defaultMerBankAccBo.setMerchantNo(dto.getMerchantNo());
            defaultMerBankAccBo.setCustomerCode(customerCode);
            tfMerchantBankAccountService.setDefaultBankAcc(defaultMerBankAccBo);
        }

        SaveMerchantBankAccountVo vo = new SaveMerchantBankAccountVo();
        vo.setAccUniqueNo(merchantBankAccount.getAccUniqueNo());

        return ResultEx.ok(vo);
    }


}
